{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# hvPlot.paths\n",
    "\n",
    "```{eval-rst}\n",
    ".. currentmodule:: hvplot\n",
    "\n",
    ".. automethod:: hvPlot.paths\n",
    "```\n",
    "\n",
    "## Backend-specific styling options\n",
    "\n",
    "```{eval-rst}\n",
    ".. backend-styling-options:: paths\n",
    "```\n",
    "\n",
    "## Examples\n",
    "\n",
    "### Basic paths plot from a DataFrame\n",
    "\n",
    "A simple set of x/y coordinates is needed to generate a `paths` plot. While looking similarly to the output of a `line` plot, the object returned is a HoloViews [Path Element](https://holoviews.org/reference/elements/bokeh/Path.html) whose key dimensions are `'x'` and `'y'`, while for a `line` plot the returned object is a [Curve Element](https://holoviews.org/reference/elements/bokeh/Curve.html) with `'x'` as key dimension and `'y'` as value dimension. This models the independence between x and y, which is for example appropriate for representing a trajectory like a hurricane track."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import hvplot.pandas  # noqa\n",
    "import pandas as pd\n",
    "\n",
    "df = pd.DataFrame({'x': [0, 1, 2, 3], 'y': [0, 0.75, 1.25, 1.5]})\n",
    "\n",
    "df.hvplot.paths(x='x', y='y', aspect='equal')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Vectorize `color` and `line_width`\n",
    "\n",
    "This example sets [`color`](option-color) and `line_width`, both referencing the `'t'` dimension of this dataset: `color` with the `'t'` string, and `line_width` with a HoloViews [`dim`](https://holoviews.org/user_guide/Style_Mapping.html) object `hv.dim('t')**2` that squares each value of `'t'`. Each sub-line of the path has its color and width computed from these expressions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import holoviews as hv\n",
    "import hvplot.pandas  # noqa\n",
    "import pandas as pd\n",
    "\n",
    "df = pd.DataFrame({'x': list(range(10)), 'y': list(range(10)), 't': list(range(1, 11))})\n",
    "\n",
    "df.hvplot.paths(\n",
    "    x='x', y='y', color='t', cmap='viridis',\n",
    "    line_width=hv.dim('t')**2, aspect='equal', \n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### From a GeoPandas dataset\n",
    "\n",
    "The `paths` method can be used directly from [GeoPandas GeoDataFrame](https://geopandas.org/en/stable/docs/reference/api/geopandas.GeoDataFrame.html) objects containing `LineString` or `MultiLineString` geometries."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import hvplot.pandas  # noqa\n",
    "import geopandas as gpd\n",
    "from shapely.geometry import LineString\n",
    "\n",
    "lines = [\n",
    "    LineString([(-112.048, 33.451), (-112.03, 33.451)]),\n",
    "    LineString([(-112.048, 33.459), (-112.03, 33.459)]),\n",
    "    LineString([(-112.048, 33.466), (-112.03, 33.466)]),\n",
    "    LineString([(-112.048, 33.44), (-112.048, 33.48)]),\n",
    "    LineString([(-112.03, 33.44), (-112.03, 33.48)]),\n",
    "]\n",
    "categories = ['residential', 'residential', 'residential', 'arterial', 'arterial']\n",
    "gdf = gpd.GeoDataFrame({'category': categories}, geometry=lines, crs='EPSG:4326')\n",
    "\n",
    "gdf.hvplot.paths(\n",
    "    color='category', cmap='category10',\n",
    "    line_width=3, tiles=True, tiles_opts=dict(alpha=0.5),\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import hvplot.pandas  # noqa\n",
    "import geopandas as gpd\n",
    "from shapely.geometry import LineString, MultiLineString\n",
    "\n",
    "lines = [\n",
    "    MultiLineString([\n",
    "        LineString([(-112.048, 33.451), (-112.03, 33.451)]),\n",
    "        LineString([(-112.048, 33.459), (-112.03, 33.459)]),\n",
    "        LineString([(-112.048, 33.466), (-112.03, 33.466)]),\n",
    "    ]),\n",
    "    MultiLineString([\n",
    "        LineString([(-112.048, 33.44), (-112.048, 33.48)]),\n",
    "        LineString([(-112.03, 33.44), (-112.03, 33.48)]),\n",
    "    ]),\n",
    "]\n",
    "categories = ['residential', 'arterial']\n",
    "gdf = gpd.GeoDataFrame({'category': categories}, geometry=lines, crs='EPSG:4326')\n",
    "\n",
    "gdf.hvplot.paths(\n",
    "    color='category', cmap='category10',\n",
    "    line_width=3, tiles=True, tiles_opts=dict(alpha=0.5),\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### From a DataFrame containing geographic coordinates\n",
    "\n",
    "*Example adapted from https://scitools.org.uk/cartopy/docs/latest/matplotlib/intro.html.*\n",
    "\n",
    "Notice how the line in blue between New York and Delhi is not straight on a flat PlateCarree map, this is because the Geodetic coordinate system is a truly spherical coordinate system, where a line between two points is defined as the shortest path between those points on the globe rather than 2d Cartesian space."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cartopy.crs as ccrs\n",
    "import hvplot.pandas  # noqa\n",
    "import pandas as pd\n",
    "\n",
    "df = pd.DataFrame({\"city\": [\"NY\", \"Delhi\"], \"lon\": [-75, 77.23], \"lat\": [43, 28.61]})\n",
    "\n",
    "common_kwargs = dict(\n",
    "    x=\"lon\",\n",
    "    y=\"lat\",\n",
    "    geo=True,\n",
    "    project=True,\n",
    "    projection=ccrs.GOOGLE_MERCATOR,\n",
    "    global_extent=True\n",
    ")\n",
    "shortest_path = df.hvplot.paths(color=\"blue\", crs=ccrs.Geodetic(), tiles=True, **common_kwargs)\n",
    "straight_path = df.hvplot.paths(color=\"grey\", line_dash=\"dashed\", **common_kwargs)\n",
    "shortest_path * straight_path"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### From an Xarray Dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import hvplot.xarray  # noqa\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import xarray as xr\n",
    "\n",
    "time = pd.date_range(\"2025-09-01\", periods=20, freq=\"6h\")\n",
    "lon = [-55.0]\n",
    "lat = [16.0]\n",
    "for _ in range(1, len(time)):\n",
    "    lon.append(lon[-1] - np.random.uniform(0.3, 1.0))\n",
    "    lat.append(lat[-1] + np.random.uniform(0.1, 0.5))\n",
    "base_speed = np.linspace(40, 120, len(time))\n",
    "noise = np.random.normal(0, 5, len(time))\n",
    "wind_speed = base_speed + noise\n",
    "ds = xr.Dataset(\n",
    "    data_vars={\"wind_speed\": ([\"time\"], wind_speed)},\n",
    "    coords={\n",
    "        \"time\": time,\n",
    "        \"lon\": (\"time\", lon),\n",
    "        \"lat\": (\"time\", lat)\n",
    "    },\n",
    ")\n",
    "\n",
    "ds.hvplot.paths(\n",
    "    x='lon', y='lat', color='wind_speed',\n",
    "    hover_cols=['time'], line_width=5, tiles=True,\n",
    ")"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
